package com.samphanie.auiu.auth.controller;

import com.samphanie.auiu.auth.feign.IThirdPartyService;
import com.samphanie.auiu.auth.service.IUserCacheService;
import com.samphanie.auiu.auth.service.IUserService;
import com.samphanie.auiu.common.constants.SmsConstants;
import com.samphanie.auiu.common.dto.*;
import com.samphanie.auiu.common.enums.MfaType;
import com.samphanie.auiu.common.exception.ApiException;
import com.samphanie.auiu.common.utils.ApiResponse;
import com.samphanie.auiu.common.utils.ResultCode;
import com.samphanie.auiu.mbg.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.data.util.Pair;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.validation.Valid;

/**
 * @author ZSY
 * @email 1451691457@qq.com
 */
@Api(tags = "授权服务中心")
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/auth")
public class AuthorizeController {

    private final IUserService userService;
    private final IUserCacheService userCacheService;
    private final IThirdPartyService thirdPartyService;

    private final RestTemplate restTemplate;

    @ApiOperation("验证用户名重复")
    @GetMapping("/validation/username")
    public boolean validateUsername(@RequestParam String username) {
        return userService.isUsernameExisted(username);
    }

    @ApiOperation("验证邮箱重复")
    @GetMapping("/validation/email")
    public boolean validateEmail(@RequestParam String email) {
        return userService.isEmailExisted(email);
    }

    @ApiOperation("验证手机号重复")
    @GetMapping("/validation/mobile")
    public boolean validateMobile(@RequestParam String mobile) {
        return userService.isMobileExisted(mobile);
    }

    @ApiOperation("新用户注册")
    @PostMapping("/register")
    public void register(@Valid @RequestBody RegisterDto registerDto) {
        userService.validateUserUniqueFields(registerDto.getUsername(), registerDto.getEmail(), registerDto.getMobile());
        val user = User.builder()
                .username(registerDto.getUsername())
                .nickname(registerDto.getNickname())
                .email(registerDto.getEmail())
                .mobile(registerDto.getMobile())
                .password(registerDto.getPassword())
                .usingMfa(true)
                .enabled(false)
                .build();
        userService.register(user);
    }

    @PostMapping( "/admin/login")
    public ApiResponse<?> adminLogin(@RequestBody AdminLoginDto loginDto) {
        MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
        parameters.set("grant_type", "password");
        parameters.set("client_id", "admin-client");
        parameters.set("client_secret", "secret");
        parameters.set("username", loginDto.getUsername());
        parameters.set("password", loginDto.getPassword());
        return restTemplate.postForEntity("http://localhost:9999/oauth/token", parameters, ApiResponse.class).getBody();
    }

    @PutMapping("/totp")
    public void sendTotp(@Valid @RequestBody SendTotpDto sendTotpDto) {
        userCacheService.retrieveUser(sendTotpDto.getMfaId())
                .flatMap(user -> userService.createTotp(user).map(code -> Pair.of(user, code)))
                .ifPresentOrElse(pair -> {
                    log.debug("totp: {}", pair.getSecond());
                    if (sendTotpDto.getMfaType() == MfaType.SMS) {
                        val sendSmsTo = SendSmsDto.builder()
                                .key(SmsConstants.SMS_CODE)
                                .message( pair.getSecond())
                                .mobile(pair.getFirst().getMobile())
                                .build();
                        thirdPartyService.sendSmsCode(sendSmsTo);
                    } else {

                        val sendEmailTo = SendEmailDto.builder()
                                .to(pair.getFirst().getEmail())
                                .subject("totp认证")
                                .template("welcome_user_email")
                                .build();
                        thirdPartyService.sendEmail(sendEmailTo);
                    }
                }, () -> {
                    throw new ApiException(ResultCode.VALIDATE_FAILED);
                });
    }

    @PostMapping("/totp")
    public void verifyTotp(@Valid @RequestBody TotpVerificationDto totpVerificationDto) {
        val result = userCacheService.verifyTotp(totpVerificationDto.getMfaId(), totpVerificationDto.getCode());
        if (result.isEmpty()) {
            throw new ApiException(ResultCode.INTERNAL_SERVER_ERROR);
        }
    }

}
